//
//Copyright 2001-2004 Stottler Henke Associates, Inc.
//All Rights Reserved.
//////////////////////////////////////////////////////////////////////

package com.stottlerhenke.simbionic.engine.core;

import java.util.*;

import com.stottlerhenke.simbionic.api.SB_Exception;
import com.stottlerhenke.simbionic.common.SB_FileException;
import com.stottlerhenke.simbionic.engine.SB_SingletonBook;
import com.stottlerhenke.simbionic.engine.file.SB_StreamReader;

/** 
 * Class for all nodes that invoke a behavior when applied.
 */
public class SB_BehaviorNode extends SB_Node {
  protected String _behaviorName;

  public SB_BehaviorNode(SB_BehaviorElement owner,int nodeID) {
    super(owner, nodeID);
    _behaviorName = "";
  }

  /**
   * Reads a single behavior node from a specification.
   * @param reader the stream reader from which to read it
   */
  public void load(SB_StreamReader reader,SB_SingletonBook book)
		throws SB_FileException 
	{
    super.load(reader,book);
    _behaviorName = reader.readPString();
  }

	public void initialize(ArrayList transitions,SB_SingletonBook book) 
		throws SB_Exception
	{
    SB_BehaviorClass behavior = book.getBehaviorRegistry().getBehaviorClass(_behaviorName);

    super.initialize(transitions,book);
    _bindings.initParamBindings( behavior.GetParams() );
	}

  public ENodeType GetNodeType() {
    return ENodeType.kBehaviorNode;
  }

  public String GetLogName() {
	  return _behaviorName;
  }

  public void Execute(SB_Entity entity, SB_ExecutionFrame contextFrame, SB_SingletonBook book)  throws SB_Exception
  {
    // only execute the node when first entering it (ie not on every
    // clock tick afterward while remaining in the node)
    if (!contextFrame.HasNodeBeenInvoked()) {
      SB_EntityData state = entity.GetState();

      // keep track of whether this node has been applied
      contextFrame.SetNodeBeenInvoked(true);

      // apply the variable bindings for the node
      _bindings.ApplyForVariables(entity, contextFrame);

      try {
        // put a new frame on the stack
        SB_ExecutionFrame newFrame = state.InvokeBehavior(_behaviorName,
            contextFrame, book);

        // bind the invoked behavior's parameters
        _bindings.ApplyForInvocation(entity, contextFrame, newFrame);

				if (!contextFrame.InvokedInterrupt())
				{
					// only clear the invoked-behavior-finished flag
					// for non-interrupt behavior invocations (otherwise
					// the interrupt behavior might overwrite the status
					// of the already-invoked normal behavior)
					contextFrame.SetInvokedDone(false);
				}

        // invoking the behavior shouldn't waste a clock tick
        state.SetDoAnotherTick(true);
      }catch(SB_Exception e){

      }
    }
  }
}